package ssau.knyazev.fractal.core;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;

import static ssau.knyazev.fractal.common.FractalConst.*;

import ssau.knyazev.core.Complex;;

public class FractalCore {

	public static Image drawDragonFractal(int width, int height, int countIterations){
		Image result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics g = result.getGraphics();
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, width, height);
		g.setColor(Color.BLACK);
		dragon(g, 200, 300, 500, 300, countIterations);
		return result;
	}
	
	private static void dragon(Graphics g, int x1, int y1, int x2, int y2, int k){
		int xn, yn;		
		if (k>0) {
		      xn =(x1+x2)/2 +(y2-y1)/2; 
		      yn =(y1+y2)/2 -(x2-x1)/2; 
		      dragon(g, x1, y1, xn, yn, k-1);
		      dragon(g, x2, y2, xn, yn, k-1);
		} else { 
			g.drawLine(x1,y1,x2,y2); 
		}
	}

	public static Image drawJuliahFractal(int width, int height, Complex c){
		Image result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics g = result.getGraphics();
		double maxX = JULIAH_MAXX;
		double minX = JULIAH_MINX;
		double maxY = JULIAH_MAXY;
		double minY = JULIAH_MINY;
		int[][] pixels = new int[width][height];
		int maxColor = 0;
		int minColor = 255;
		for (int i = 0; i < height; i++){
			for (int j = 0; j < width; j++){
				double x = minX + j*(maxX-minX)/width;
				double y = minY + i*(maxY-minY)/height;
				boolean flag = true;
				Complex z0 = new Complex((float)x, (float)y);
				Complex zk = c.add(z0.multy(z0));
				int color = 0;
				for (int k = 0; k <= 255 && flag; k++){
					color = k;
					z0 = zk;
					zk = c.add(z0.multy(z0));
					Complex temp = zk.sub(z0);
					if (temp.norm(temp) > 4 || temp.norm(temp) == 0){
						flag = false;
					}				
				}
				color = (color == 255) ? 0 : color;
				pixels[i][j] = color;
				if (color > maxColor){
					maxColor = color;
				}
				if (color < minColor){
					minColor = color;
				}
			}
		}
		double a = 255/(maxColor - minColor);
		double b = -a*minColor;
		for (int i = 0; i < height; i++){
			for (int j = 0; j < width; j++){
				int newColor = pixels[i][j];
				newColor = (int) (a*newColor + b);
				g.setColor(new Color(newColor, 0, newColor));
				g.drawLine(i, j, i, j);
			}
		}
		return result;
	}
	
	public static Image drawMandelbrotFractal(int width, int height){
		Image result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics g = result.getGraphics();
		double maxX = MAND_MAXX;
		double minX = MAND_MINX;
		double maxY = MAND_MAXY;
		double minY = MAND_MINY;
		int[][] pixels = new int[width][height];
		int maxColor = 0;
		int minColor = 255;
		for (int i = 0; i < height; i++){
			for (int j = 0; j < width; j++){
				double x = minX + j*(maxX-minX)/width;
				double y = minY + i*(maxY-minY)/height;
				Complex c = new Complex((float)x, (float)y);
				boolean flag = true;
				Complex z0 = new Complex();
				Complex zk = c.add(z0.multy(z0));
				int color = 0;
				for (int k = 0; k <= 455 && flag; k++){
					color = k;
					z0 = zk;
					zk = c.add(z0.multy(z0));
					Complex temp = zk.sub(z0);
					if (temp.norm(temp) > 4){
						flag = false;
					}				
				}
				color = (color >= 455) ? 0 : color;
				pixels[j][i] = color;
				if (color > maxColor){
					maxColor = color;
				}
				if (color < minColor){
					minColor = color;
				}
			}
		}
		double a = 254/((double)maxColor - (double)minColor);
		double b = 1 - a*minColor;
		System.out.println(a);
		System.out.println(b);
		for (int i = 0; i < height; i++){
			for (int j = 0; j < width; j++){
				int newColor = pixels[i][j];
				newColor = (int) (a*newColor + b);
				//newColor = (int)(newColor * 4.5);
				newColor = (newColor > 255) ? 255: newColor;
				g.setColor(new Color(newColor, newColor, 0));
				g.drawLine(i, j, i, j);
			}
		}
		return result;
	}
}
